home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
JCSM Shareware Collection 1993 November
/
JCSM Shareware Collection - 1993-11.iso
/
cl720
/
tsrtoo15.lzh
/
TSR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-04
|
51KB
|
1,975 lines
/*
tsr.C
Version 1.5
Generate TSR .ASM file or view resident TSRs.
Command-line format:
tsr options tsrspec
options = map | [hotkey] [include] [setup_cleanup] [stack] [xparse]
map = ("/"|"-") "m"
hotkey = ("/"|"-") "h" x
include = ("/"|"-") "i"
setup_cleanup = ("/"|"-") "sc"
stack = ("/"|"-") "s" y
xparse = ("/"|"-") "x"
x is either "A"-"Z" or "0"-"9" (default is T)
y is a byte value from 256 to 8192 (default is 256)
tsrspec defines the .TSR file to be TSRed
Copyright (C) 1993, Geoff Friesen B.Sc.
All rights reserved.
Developed with: Borland C++ 3.1
*/
#if !defined(__LARGE__)
#error Large Memory Model Expected
#endif
#include <ctype.H>
#include <dir.H>
#include <dos.H>
#include <process.H>
#include <stdio.H>
#include <stdlib.H>
#include <string.H>
#define OK 0
#define ERROR !OK
#define IGNORE 1
#define FREEMCB 0
#define BLOCMCB 'M'
#define LASTMCB 'Z'
#define KEYOFS 0x103
#define SIGOFS 0x10d
/* --------------------------------------------------------------------- */
char *listing1 =
"\n\n"
"_TEXT\t\tSEGMENT\tBYTE PUBLIC 'CODE'\n"
"\t\tASSUME\tcs:_TEXT, ds:NOTHING, es:NOTHING, ss:NOTHING\n"
"\t\tORG\t100h\n"
"\n"
"CR\t\tEQU\t13\n"
"LF\t\tEQU\t10\n"
"TAB\t\tEQU\t9\n"
"\n"
"INACTIVE\tEQU\t0\t\t; TSR not active.\n"
"TRIGGERED\tEQU\t1\t\t; TSR triggered.\n"
"ACTIVE\t\tEQU\t2\t\t; TSR active.\n"
"\n"
"tsr:\n"
"\t\tjmp\tNEAR PTR install\n"
"\n"
"; ----------------------- ;\n"
"; Personal Identification ;\n"
"; ----------------------- ;\n"
"\n"
"key\t\tDB\t'";
/* --------------------------------------------------------------------- */
char *listing2 =
"'\t\t; Hotkey character.\n"
"scancode\tDB\t";
/* --------------------------------------------------------------------- */
char *listing3 =
"\t\t; Activation scancode.\n"
"\t\tDB\t0\n"
"\t\tDB\t2\t\t; Version number.\n"
"\t\tDW\t_main\t\t; Application start address.\n"
"\t\tDW\tinstallsec\t; Application end address+1.\n"
"\t\tDW\t0\t\t; Reserved.\n"
"signature\tDB\t";
/* --------------------------------------------------------------------- */
char *listing4 =
"\t; Our signature in memory.\n"
"SIGLENGTH\tEQU\t$-signature\t; Length of this signature.\n"
"\t\tDB\t0\n"
"\n"
"; --------------------- ;\n"
"; Resident Data Section ;\n"
"; --------------------- ;\n"
"\n"
"beepf\t\tDB\t0\t\t; Beep when TSR triggered flag.\n"
"critdisk\tDB\t0\t\t; Critical disk flag.\n"
"criterr\t\tDD\t?\t\t; Address of critical error flag.\n"
"critsec\t\tDD\t?\t\t; Address of critical section flag.\n"
"dta\t\tDD\t?\t\t; Saved DTA address.\n"
"errax\t\tDW\t?\t\t; Saved extended error info.\n"
"errbx\t\tDW\t?\n"
"errcx\t\tDW\t?\n"
"oldint8h\tDD\t?\t\t; Old interrupt 8h vector.\n"
"oldint8h_\tDD\t?\n"
"oldint9h\tDD\t?\t\t; Old interrupt 9h vector.\n"
"oldint9h_\tDD\t?\n"
"oldint13h\tDD\t?\t\t; Old interrupt 13h vector.\n"
"oldint16h\tDD\t?\t\t; Old interrupt 16h vector.\n"
"oldint16h_\tDD\t?\n"
"oldint1bh\tDD\t?\t\t; Old interrupt 1bh vector.\n"
"oldint1ch\tDD\t?\t\t; Old interrupt 1ch vector.\n"
"oldint1ch_\tDD\t?\n"
"oldint23h\tDD\t?\t\t; Old interrupt 23h vector.\n"
"oldint24h\tDD\t?\t\t; Old interrupt 24h vector.\n"
"oldint28h\tDD\t?\t\t; Old interrupt 28h vector.\n"
"oldint2fh\tDD\t?\t\t; Old interrupt 2fh vector.\n"
"port61h\t\tDB\t?\t\t; Current value in port 61h.\n"
"psp_\t\tDW\t?\t\t; Saved PSP.\n"
"savesp\t\tDW\t?\t\t; Saved stack pointer.\n"
"savess\t\tDW\t?\t\t; Saved stack segment.\n"
"tsr_state\tDB\tINACTIVE\t; TSR state.\n"
"XMS_driver\tDD\t0\t\t; Address of XMS driver.\n"
"XMS_inuse\tDB\t0\t\t; XMS inuse flag.\n"
"\n"
"; --------------------- ;\n"
"; Resident Code Section ;\n"
"; --------------------- ;\n"
"\n"
"; ----------------------- ;\n"
"; New interrupt 8h vector ;\n"
"; ----------------------- ;\n"
"\n"
"newint8h\tPROC\tFAR\n"
"\t\tpushf\n"
"\t\tcall\tDWORD PTR oldint8h\n"
"\n"
"\t\tcmp\tBYTE PTR tsr_state, TRIGGERED\n"
"\t\tjnz\tnewint8h1\n"
"\n"
"\t\tpush\tax\n"
"\t\tpush\tbx\n"
"\t\tpush\tes\n"
"\n"
"\t\tles\tbx, DWORD PTR criterr\n"
"\t\tmov\tal, es:[bx]\n"
"\n"
"\t\tcmp\tal, 0\n"
"\n"
"\t\tpop\tes\n"
"\t\tpop\tbx\n"
"\t\tpop\tax\n"
"\n"
"\t\tjnz\tnewint8h1\n"
"\n"
"\t\tpush\tax\n"
"\t\tpush\tbx\n"
"\t\tpush\tes\n"
"\n"
"\t\tles\tbx, DWORD PTR critsec\n"
"\t\tmov\tal, es:[bx]\n"
"\n"
"\t\tcmp\tal, 0\n"
"\n"
"\t\tpop\tes\n"
"\t\tpop\tbx\n"
"\t\tpop\tax\n"
"\n"
"\t\tjnz\tnewint8h1\n"
"\n"
"\t\tcmp\tBYTE PTR critdisk, 0\n"
"\t\tjnz\tnewint8h1\n"
"\n"
"\t\tcmp\tBYTE PTR XMS_inuse, 0\n"
"\t\tjnz\tnewint8h1\n"
"\n"
"\t\tmov\tBYTE PTR tsr_state, ACTIVE\n"
"\n"
"\t\tcall\tlaunch\n"
"\n"
"\t\tmov\tBYTE PTR tsr_state, INACTIVE\n"
"newint8h1:\n"
"\t\tiret\n"
"newint8h\tENDP\n"
"\n"
"; ----------------------- ;\n"
"; New interrupt 9h vector ;\n"
"; ----------------------- ;\n"
"\n"
"newint9h\tPROC\tFAR\n"
"\t\tpush\tax\n"
"\n"
"\t\tin\tal, 60h\t\t; Examine scan code.\n"
"\n"
"\t\tcmp\tal, scancode\t; Does it match our scan code?\n"
"\t\tjz\tnewint9h2\t; Yes, branch.\n"
"newint9h1:\n"
"\t\tpop\tax\t\t; Exit to original handler.\n"
"\t\tjmp\tDWORD PTR oldint9h\n"
"newint9h2:\n"
"\t\tpush\tes\t\t; Check for simultaneous ALT press.\n"
"\t\tmov\tax, 0\n"
"\t\tmov\tes, ax\n"
"\n"
"\t\tmov\tal, es:[417h]\t; Get shift status byte.\n"
"\t\tand\tal, 15\t\t; Remove toggle data.\n"
"\t\tcmp\tal, 8\t\t; ALT (alone) pressed?\n"
"\n"
"\t\tpop\tes\n"
"\t\tjnz\tnewint9h1\t; No, branch.\n"
"\n"
"\t\tin\tal, 61h\t\t; Acknowledge scan code.\n"
"\t\tjmp\t$+2\n"
"\t\tmov\tah, al\n"
"\t\tor\tal, 10000000b\n"
"\t\tout\t61h, al\n"
"\t\tjmp\t$+2\n"
"\t\tmov\tal, ah\n"
"\t\tout\t61h, al\n"
"\t\tjmp\t$+2\n"
"\n"
"\t\tcmp\tBYTE PTR tsr_state, INACTIVE\n"
"\t\tjnz\tnewint9h4\t; Branch if TSR not inactive.\n"
"\n"
"\t\tcmp\tbeepf, 0\t; Can we beep?\n"
"\t\tjz\tnewint9h3\t; No, branch.\n"
"\n"
"\t\tin\tal, 61h\t\t; Save port value.\n"
"\t\tmov\tport61h, al\n"
"\n"
"\t\tand\tal, 0fch\t; Disconnect speaker.\n"
"\t\tout\t61h, al\n"
"\n"
"\t\tsti\n"
"\t\tcall\t_beep\t\t; Generate a beep.\n"
"\t\tcli\n"
"\n"
"\t\tmov\tal, port61h\t; Restore port value.\n"
"\t\tout\t61h, al\n"
"newint9h3:\n"
"\t\tmov\tBYTE PTR tsr_state, TRIGGERED\n"
"newint9h4:\n"
"\t\tmov\tal, 20h\t\t; Reset 8259 PIC.\n"
"\t\tout\t20h, al\n"
"\n"
"\t\tpop\tax\n"
"\n"
"\t\tiret\n"
"newint9h\tENDP\n"
"\n"
"; ------------------------ ;\n"
"; New interrupt 13h vector ;\n"
"; ------------------------ ;\n"
"\n"
"newint13h\tPROC\tFAR\n"
"\t\tmov\tBYTE PTR critdisk, 1\n"
"\n"
"\t\tpushf\n"
"\t\tcall\tDWORD PTR oldint13h\n"
"\n"
"\t\tmov\tBYTE PTR critdisk, 0\n"
"\n"
"\t\tsti\n"
"\n"
"\t\tret\t2\t\t; Return without original flags.\n"
"newint13h\tENDP\n"
"\n"
"; ------------------------ ;\n"
"; New interrupt 1bh vector ;\n"
"; ------------------------ ;\n"
"\n"
"newint1bh\tPROC\tFAR\n"
"\t\tiret\n"
"newint1bh\tENDP\n"
"\n"
"; ------------------------ ;\n"
"; New interrupt 23h vector ;\n"
"; ------------------------ ;\n"
"\n"
"newint23h\tPROC\tFAR\n"
"\t\tiret\n"
"newint23h\tENDP\n"
"\n"
"; ------------------------ ;\n"
"; New interrupt 24h vector ;\n"
"; ------------------------ ;\n"
"\n"
"newint24h\tPROC\tFAR\n"
"\t\tmov\tax, 3\t\t; Fail code.\n"
"\n"
"\t\tiret\n"
"newint24h\tENDP\n"
"\n"
"; ------------------------ ;\n"
"; New interrupt 28h vector ;\n"
"; ------------------------ ;\n"
"\n"
"newint28h\tPROC\tFAR\n"
"\t\tpushf\n"
"\t\tcall\tDWORD PTR oldint28h\n"
"\n"
"\t\tcmp\tBYTE PTR tsr_state, TRIGGERED\n"
"\t\tjnz\tnewint28h1\n"
"\n"
"\t\tpush\tax\n"
"\t\tpush\tbx\n"
"\t\tpush\tes\n"
"\n"
"\t\tles\tbx, DWORD PTR criterr\n"
"\t\tmov\tal, es:[bx]\n"
"\n"
"\t\tcmp\tal, 0\n"
"\n"
"\t\tpop\tes\n"
"\t\tpop\tbx\n"
"\t\tpop\tax\n"
"\n"
"\t\tjnz\tnewint28h1\n"
"\n"
"\t\tpush\tax\n"
"\t\tpush\tbx\n"
"\t\tpush\tes\n"
"\n"
"\t\tles\tbx, DWORD PTR critsec\n"
"\t\tmov\tal, es:[bx]\n"
"\n"
"\t\tcmp\tal, 1\n"
"\n"
"\t\tpop\tes\n"
"\t\tpop\tbx\n"
"\t\tpop\tax\n"
"\n"
"\t\tja\tnewint28h1\n"
"\n"
"\t\tcmp\tBYTE PTR critdisk, 0\n"
"\t\tjnz\tnewint28h1\n"
"\n"
"\t\tcmp\tBYTE PTR XMS_inuse, 0\n"
"\t\tjnz\tnewint28h1\n"
"\n"
"\t\tmov\tBYTE PTR tsr_state, ACTIVE\n"
"\n"
"\t\tcall\tlaunch\n"
"\n"
"\t\tmov\tBYTE PTR tsr_state, INACTIVE\n"
"newint28h1:\n"
"\t\tiret\n"
"newint28h\tENDP\n"
"\n"
"; ------------------------ ;\n"
"; New interrupt 2fh vector ;\n"
"; ------------------------ ;\n"
"\n"
"newint2fh\tPROC\tFAR\n"
"\t\tcmp\tax, 4310h\n"
"\t\tjz\tnewint2fh1\n"
"\n"
"\t\tjmp\tDWORD PTR cs:oldint2fh\n"
"newint2fh1:\n"
"\t\tmov\tbx, OFFSET XMS_rdriver\n"
"\t\tpush\tcs\n"
"\t\tpop\tes\n"
"\n"
"\t\tiret\n"
"newint2fh\tENDP\n"
"\n"
"; ------------------------------ ;\n"
"; Launch: Launch TSR Application ;\n"
"; ------------------------------ ;\n"
"\n"
"\t\tASSUME\tds:_TEXT, es:_TEXT, ss:_TEXT\n"
"\n"
"launch\t\tPROC\tNEAR\n"
"\t\tmov\tcs:savess, ss\t; Switch stacks.\n"
"\t\tmov\tcs:savesp, sp\n"
"\t\tmov\tsp, cs\n"
"\t\tmov\tss, sp\n"
"\t\tlea\tsp, stack_\n"
"\t\tsti\n"
"\n"
"\t\tcld\n"
"\t\tpush\tax\n"
"\t\tpush\tbx\n"
"\t\tpush\tcx\n"
"\t\tpush\tdx\n"
"\t\tpush\tsi\n"
"\t\tpush\tdi\n"
"\t\tpush\tbp\n"
"\t\tpush\tds\n"
"\t\tpush\tes\n"
"\n"
"\t\tpush\tcs\n"
"\t\tpop\tds\n"
"\n"
"\t\tmov\tax, 351bh\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint1bh, bx\n"
"\t\tmov\tWORD PTR oldint1bh [2], es\n"
"\n"
"\t\tmov\tax, 3523h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint23h, bx\n"
"\t\tmov\tWORD PTR oldint23h [2], es\n"
"\n"
"\t\tmov\tax, 3524h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint24h, bx\n"
"\t\tmov\tWORD PTR oldint24h [2], es\n"
"\n"
"\t\tlea\tdx, newint1bh\n"
"\t\tmov\tax, 251bh\n"
"\t\tint\t21h\n"
"\n"
"\t\tlea\tdx, newint23h\n"
"\t\tmov\tax, 2523h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlea\tdx, newint24h\n"
"\t\tmov\tax, 2524h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tah, 62h\t\t; Save current PSP.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tpsp_, bx\n"
"\n"
"\t\tmov\tbx, cs\t\t; Set PSP to our own.\n"
"\t\tmov\tah, 50h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tah, 2fh\t\t; Save current DTA.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR dta, bx\n"
"\t\tmov\tWORD PTR dta [2], es\n"
"\n"
"\t\tmov\tdx, 80h\t\t; Set DTA to our own.\n"
"\t\tmov\tah, 1ah\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tbx, 0\t\t; Must be zero.\n"
"\t\tmov\tah, 59h\t\t; Save extended error info.\n"
"\t\tint\t21h\n"
"\n"
"\t\tpush\tcs\t\t; DS destroyed by function.\n"
"\t\tpop\tds\n"
"\n"
"\t\tmov\terrax, ax\n"
"\t\tmov\terrbx, bx\n"
"\t\tmov\terrcx, cx\n"
"\n"
"\t\tmov\tax, 3508h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint8h_, bx\n"
"\t\tmov\tWORD PTR oldint8h_ [2], es\n"
"\n"
"\t\tmov\tax, 3509h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint9h_, bx\n"
"\t\tmov\tWORD PTR oldint9h_ [2], es\n"
"\n"
"\t\tmov\tax, 3516h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint16h_, bx\n"
"\t\tmov\tWORD PTR oldint16h_ [2], es\n"
"\n"
"\t\tmov\tax, 351ch\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint1ch_, bx\n"
"\t\tmov\tWORD PTR oldint1ch_ [2], es\n"
"\n"
"\t\tlds\tdx, cs:oldint8h\n"
"\t\tmov\tax, 2508h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, cs:oldint9h\n"
"\t\tmov\tax, 2509h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, cs:oldint16h\n"
"\t\tmov\tax, 2516h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, cs:oldint1ch\n"
"\t\tmov\tax, 251ch\n"
"\t\tint\t21h\n"
"\n"
"\t\tpush\tcs\t\t; Restore DS.\n"
"\t\tpop\tds\n"
"launch1:\n"
"\t\tmov\tah, 1\t\t; Remove unwanted keys.\n"
"\t\tint\t16h\n"
"\t\tjz\tlaunch2\n"
"\n"
"\t\tmov\tah, 0\n"
"\t\tint\t16h\n"
"\t\tjmp\tSHORT launch1\n"
"launch2:\n"
"\t\tin\tal, 61h\t\t; Save port value.\n"
"\t\tmov\tport61h, al\n"
"\n"
"\t\tand\tal, 0fch\t; Disconnect speaker.\n"
"\t\tout\t61h, al\n"
"\n"
"\t\tpush\tcs\t\t; Restore ES.\n"
"\t\tpop\tes\n"
"\n"
"\t\tmov\tax, 2\t\t; Hide mouse cursor.\n"
"\t\tint\t33h\n"
"\n"
"\t\tcall\t_main\t\t; Invoke app entry point.\n"
"\n"
"\t\tmov\tax, 1\t\t; Show mouse cursor.\n"
"\t\tint\t33h\n"
"\n"
"\t\tmov\tal, 61h\t\t; Restore port value.\n"
"\t\tout\t61h, al\n"
"\n"
"\t\tpush\tds\n"
"\n"
"\t\tmov\tax, 2508h\n"
"\t\tlds\tdx, cs:oldint8h_\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 2509h\n"
"\t\tlds\tdx, cs:oldint9h_\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 2516h\n"
"\t\tlds\tdx, cs:oldint16h_\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 251ch\n"
"\t\tlds\tdx, cs:oldint1ch_\n"
"\t\tint\t21h\n"
"\n"
"\t\tpop\tds\n"
"\n"
"\t\tmov\tbx, 0\t\t; Must be zero.\n"
"\t\tlea\tdx, errax\t; Point to info structure.\n"
"\t\tmov\tax, 5d0ah\t; Restore extended error info.\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, cs:dta\t; Restore DTA.\n"
"\t\tmov\tah, 1ah\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tbx, cs:psp_\t; Restore PSP.\n"
"\t\tmov\tah, 50h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, cs:oldint24h\n"
"\t\tmov\tax, 2524h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, cs:oldint23h\n"
"\t\tmov\tax, 2523h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, cs:oldint1bh\n"
"\t\tmov\tax, 251bh\n"
"\t\tint\t21h\n"
"\n"
"\t\tpop\tes\n"
"\t\tpop\tds\n"
"\t\tpop\tbp\n"
"\t\tpop\tdi\n"
"\t\tpop\tsi\n"
"\t\tpop\tdx\n"
"\t\tpop\tcx\n"
"\t\tpop\tbx\n"
"\t\tpop\tax\n"
"\n"
"\t\tcli\t\t\t; Switch stacks.\n"
"\t\tmov\tss, cs:savess\n"
"\t\tmov\tsp, cs:savesp\n"
"\n"
"\t\tret\n"
"launch\t\tENDP\n"
"\n"
"; --------- ;\n"
"; SOUND API ;\n"
"; --------- ;\n"
"\n"
"; ----------------- ;\n"
"; void beep (void); ;\n"
"; ----------------- ;\n"
"\n"
"_beep\t\tPROC\tNEAR\n"
"\t\tpush\tax\n"
"\t\tpush\tbx\n"
"\t\tpush\tcx\n"
"\t\tpush\tdx\n"
"\t\tpush\tds\n"
"\t\tpush\tes\n"
"\n"
"\t\tpush\tcs\n"
"\t\tpop\tds\n"
"\n"
"\t\tmov\tax, 1000\n"
"\t\tpush\tax\n"
"\t\tcall\t_sound\n"
"\t\tpop\tcx\n"
"\n"
"\t\tmov\tax, 6\n"
"\t\tpush\tax\n"
"\t\tcall\t_pause\n"
"\t\tpop\tcx\n"
"\n"
"\t\tcall\t_nosound\n"
"\n"
"\t\tpop\tes\n"
"\t\tpop\tds\n"
"\t\tpop\tdx\n"
"\t\tpop\tcx\n"
"\t\tpop\tbx\n"
"\t\tpop\tax\n"
"\n"
"\t\tret\n"
"_beep\t\tENDP\n"
"\n"
"; -------------------- ;\n"
"; void nosound (void); ;\n"
"; -------------------- ;\n"
"\n"
"_nosound\tPROC\tNEAR\n"
"\t\tin\tal, 61h\t\t; Deactivate sound latch.\n"
"\t\tand\tal, 0fch\n"
"\t\tout\t61h, al\n"
"\n"
"\t\tret\n"
"_nosound\tENDP\n"
"\n"
"; ---------------------------- ;\n"
"; void pause (unsigned ticks); ;\n"
"; ---------------------------- ;\n"
"\n"
"_pause\t\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tmov\tax, 40h\n"
"\t\tmov\tes, ax\n"
"\n"
"\t\tmov\tax, [bp+4]\t; Get ticks argument.\n"
"\t\tmov\tcx, es:[6ch]\t; Get timer value.\n"
"\t\tadd\tcx, ax\t\t; Compute ending time.\n"
"_pause1:\n"
"\t\tmov\tax, es:[6ch]\t; Get timer value.\n"
"\t\tcmp\tax, cx\t\t; Finished delaying?\n"
"\t\tjnz\t_pause1\t\t; No, branch.\n"
"\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_pause\t\tENDP\n"
"\n"
"; -------------------------------- ;\n"
"; void sound (unsigned frequency); ;\n"
"; -------------------------------- ;\n"
"\n"
"_sound\t\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tmov\tbx, [bp+4]\t; Get frequency.\n"
"\t\tmov\tax, 13533\t; Get 1,193,181 into DX:AX.\n"
"\t\tmov\tdx, 18\n"
"\n"
"\t\tcmp\tdx, bx\t\t; Min. frequency must exceed 18 HZ.\n"
"\t\tjnb\t_sound2\t\t; Branch if less.\n"
"\n"
"\t\tdiv\tbx\t\t; Compute 1,193,181/frequency.\n"
"\t\tmov\tbx, ax\n"
"\t\tin\tal, 61h\t\t; Check if sound latch is active.\n"
"\n"
"\t\ttest\tal, 3\t\t; Is sound latch active?\n"
"\t\tjne\t_sound1\t\t; Yes, branch.\n"
"\n"
"\t\tor\tal, 3\t\t; Turn on sound latch.\n"
"\t\tout\t61h, al\n"
"\t\tmov\tal, 0b6h\t; Program 8253 timer channel C.\n"
"\t\tout\t43h, al\n"
"_sound1:\n"
"\t\tmov\tal, bl\t\t; Output division result ...\n"
"\t\tout\t42h, al\t\t; ... to set the frequency.\n"
"\t\tmov\tal, bh\n"
"\t\tout\t42h, al\n"
"_sound2:\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_sound\t\tENDP\n"
"\n"
"; ------- ;\n"
"; XMS API ;\n"
"; ------- ;\n"
"\n"
"; ----------------------------------------------------- ;\n"
"; XMS_rdriver - redirected device driver for XMS access ;\n"
"; ----------------------------------------------------- ;\n"
"\n"
"XMS_rdriver\tPROC\tFAR\n"
"\t\tmov\tBYTE PTR cs:XMS_inuse, 1\n"
"\t\tcall\tDWORD PTR cs:XMS_driver\n"
"\t\tmov\tBYTE PTR cs:XMS_inuse, 0\n"
"\t\tret\n"
"XMS_rdriver\tENDP\n"
"\n"
"; -------------------------------- ;\n"
"; int XMS_Alloc (unsigned nkilos); ;\n"
"; -------------------------------- ;\n"
"\n"
"_XMS_Alloc\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tcall\tNEAR PTR _XMS_Exists\n"
"\t\tjz\t_XMS_Alloc1\t; Branch if driver not installed.\n"
"\n"
"\t\tmov\tah, 9\t\t; Allocate extended memory block.\n"
"\t\tmov\tdx, [bp+4]\t; Get number of kilos.\n"
"\t\tcall\tFAR PTR XMS_rdriver\n"
"\n"
"\t\tor\tax, ax\t\t; Error?\n"
"\t\tjz\t_XMS_Alloc1\t; Yes, branch.\n"
"\n"
"\t\tmov\tax, dx\t\t; Return handle.\n"
"_XMS_Alloc1:\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_XMS_Alloc\tENDP\n"
"\n"
"; ----------------------- ;\n"
"; int XMS_Copy (EMMS *x); ;\n"
"; ----------------------- ;\n"
"\n"
"_XMS_Copy\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tpush\tsi\n"
"\n"
"\t\tcall\tNEAR PTR _XMS_Exists\n"
"\t\tjz\t_XMS_Copy1\t; Branch if driver not installed.\n"
"\n"
"\t\tmov\tah, 11\t\t; Copy memory block.\n"
"\t\tmov\tsi, [bp+4]\t; Get address of EMMS block.\n"
"\t\tcall\tFAR PTR XMS_rdriver\n"
"_XMS_Copy1:\n"
"\t\tpop\tsi\n"
"\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_XMS_Copy\tENDP\n"
"\n"
"; ---------------------- ;\n"
"; int XMS_Exists (void); ;\n"
"; ---------------------- ;\n"
"\n"
"_XMS_Exists\tPROC\tNEAR\n"
"\t\tmov\tax, WORD PTR XMS_driver\n"
"\t\tor\tax, WORD PTR XMS_driver [2]\n"
"\t\tret\n"
"_XMS_Exists\tENDP\n"
"\n"
"; ------------------------------- ;\n"
"; int XMS_Free (unsigned handle); ;\n"
"; ------------------------------- ;\n"
"\n"
"_XMS_Free\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tcall\tNEAR PTR _XMS_Exists\n"
"\t\tjz\t_XMS_Free1\t; Branch if driver not installed.\n"
"\n"
"\t\tmov\tah, 10\t\t; Free extended memory block.\n"
"\t\tmov\tdx, [bp+4]\t; Get handle.\n"
"\t\tcall\tFAR PTR XMS_rdriver\n"
"_XMS_Free1:\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_XMS_Free\tENDP\n"
"\n"
"; -------------------------------- ;\n"
"; long XMS_Lock (unsigned handle); ;\n"
"; -------------------------------- ;\n"
"\n"
"_XMS_Lock\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tcall\tNEAR PTR _XMS_Exists\n"
"\t\tjz\t_XMS_Lock1\t; Branch if driver not installed.\n"
"\n"
"\t\tmov\tah, 12\t\t; Lock extended memory block.\n"
"\t\tmov\tdx, [bp+4]\t; Get handle.\n"
"\t\tcall\tFAR PTR XMS_rdriver\n"
"\n"
"\t\tor\tax, ax\t\t; Error?\n"
"\t\tjz\t_XMS_Lock1\t; Yes, branch.\n"
"\n"
"\t\tmov\tax, bx\t\t; Finish computing 32-bit address.\n"
"\t\tjmp\tSHORT _XMS_Lock2\n"
"_XMS_Lock1:\n"
"\t\txor\tdx, dx\n"
"_XMS_Lock2:\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_XMS_Lock\tENDP\n"
"\n"
"; --------------------------------------------------------- ;\n"
"; int XMS_Query (unsigned *nkilos, unsigned *maxblocksize); ;\n"
"; --------------------------------------------------------- ;\n"
"\n"
"_XMS_Query\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tcall\tNEAR PTR _XMS_Exists\n"
"\t\tjz\t_XMS_Query1\t; Branch if driver not installed.\n"
"\n"
"\t\tmov\tah, 8\t\t; Query free extended memory.\n"
"\t\tcall\tFAR PTR XMS_rdriver\n"
"\n"
"\t\tor\tax, ax\t\t; Error?\n"
"\t\tjz\t_XMS_Query1\t; Yes, branch.\n"
"\n"
"\t\tmov\tbx, [bp+4]\t; Save number of kilobytes.\n"
"\t\tmov\t[bx], ax\n"
"\n"
"\t\tmov\tbx, [bp+6]\t; Save largest block size.\n"
"\t\tmov\t[bx], dx\n"
"_XMS_Query1:\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_XMS_Query\tENDP\n"
"\n"
"; --------------------------------------------------- ;\n"
"; int XMS_Realloc (unsigned handle, unsigned nkilos); ;\n"
"; --------------------------------------------------- ;\n"
"\n"
"_XMS_ReAlloc\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tcall\tNEAR PTR _XMS_Exists\n"
"\t\tjz\t_XMS_Realloc1\t; Branch if driver not installed.\n"
"\n"
"\t\tmov\tah, 15\t\t; Reallocate extended memory block.\n"
"\t\tmov\tbx, [bp+6]\t; Get new memory length in kilos.\n"
"\t\tmov\tdx, [bp+4]\t; Get handle.\n"
"\t\tcall\tFAR PTR XMS_rdriver\n"
"_XMS_Realloc1:\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_XMS_Realloc\tENDP\n"
"\n"
"; --------------------------------- ;\n"
"; int XMS_Unlock (unsigned handle); ;\n"
"; --------------------------------- ;\n"
"\n"
"_XMS_Unlock\tPROC\tNEAR\n"
"\t\tpush\tbp\n"
"\t\tmov\tbp, sp\n"
"\n"
"\t\tcall\tNEAR PTR _XMS_Exists\n"
"\t\tjz\t_XMS_Unlock1\t; Branch if driver not installed.\n"
"\n"
"\t\tmov\tah, 13\t\t; Unlock extended memory block.\n"
"\t\tmov\tdx, [bp+4]\t; Get handle.\n"
"\t\tcall\tFAR PTR XMS_rdriver\n"
"_XMS_Unlock1:\n"
"\t\tpop\tbp\n"
"\t\tret\n"
"_XMS_Unlock\tENDP\n\n";
/* --------------------------------------------------------------------- */
char *listing5 =
"\n"
"; ------------------------- ;\n"
"; Installation Data Section ;\n"
"; ------------------------- ;\n"
"\n"
"installsec:\n"
"\n"
"ctailaddr\tDW\t81h\t\t; Command tail address.\n"
"psp\t\tDW\t?\t\t; PSP of \"searched\" TSR.\n"
"\n"
"scancodes\tDB\t30,48,46,32,18,33,34,35,23,36,37,38,50 ; A-M\n"
"\t\tDB\t49,24,25,16,19,31,20,22,47,17,45,21,44 ; N-Z\n"
"\t\tDB\t11,02,03,04,05,06,07,08,09,10 ; 0-9\n"
"\n"
"tsr_delmsg\tDB\tCR, LF\n"
"\t\tDB\t\"successfully uninstalled\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n"
"tsr_keymsg\tDB\tCR, LF\n"
"\t\tDB\t\"hotkey = ALT-\"\n"
"tsr_keymsg1\tDB\t?\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n"
"tsr_errmsg1\tDB\tCR, LF\n"
"\t\tDB\t\"invalid DOS version (must be 3.30 or higher)\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n"
"tsr_errmsg2\tDB\tCR, LF\n"
"\t\tDB\t\"invalid character on command line\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n"
"tsr_errmsg3\tDB\tCR, LF\n"
"\t\tDB\t\"invalid option\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n"
"tsr_errmsg4\tDB\tCR, LF\n"
"\t\tDB\t\"not in memory\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n"
"tsr_errmsg5\tDB\tCR, LF\n"
"\t\tDB\t\"unable to uninstall\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n"
"tsr_errmsg6\tDB\tCR, LF\n"
"\t\tDB\t\"invalid hotkey character\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n";
/* --------------------------------------------------------------------- */
char *listing6 =
"tsr_errmsg7\tDB\tCR, LF\n"
"\t\tDB\t\"unable to setup\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n";
/* --------------------------------------------------------------------- */
char *listing7 =
"tsr_errmsg8\tDB\tCR, LF\n"
"\t\tDB\t\"unable to completely uninstall * \"\n"
"\t\tDB\t\"system unstable * please reboot\"\n"
"\t\tDB\tCR, LF\n"
"\t\tDB\t'$'\n"
"\n"
"ver\t\tDB\t?\t\t; Major portion of DOS version.\n"
"\n"
"; ------------------------- ;\n"
"; Installation Code Section ;\n"
"; ------------------------- ;\n"
"\n"
"install:\n"
"\t\tlea\tbx, _title\t; Display suitable title.\n"
"\t\tmov\tdx, [bx]\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tah, 30h\t\t; Obtain DOS version number.\n"
"\t\tint\t21h\n"
"\n"
"\t\tcmp\tal, 3\t\t; Test major portion.\n"
"\t\tjb\tinstall1\t; Branch if less that 3.\n"
"\t\tja\tinstall2\t; Branch if greater than 3.\n"
"\n"
"\t\tcmp\tah, 30\t\t; Test minor portion.\n"
"\t\tjae\tinstall2\t; Branch if >= 30.\n"
"install1:\n"
"\t\tlea\tdx, tsr_errmsg1\t; Display error message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 4c01h\t; Exit with error code 1.\n"
"\t\tint\t21h\n"
"install2:\n"
"\t\tmov\tver, al\t\t; Save major portion of version.\n"
"\n"
"\t\tmov\tax, 5d06h\t; Obtain critical error flag.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, ds\n"
"\n"
"\t\tpush\tcs\t\t; Restore DS.\n"
"\t\tpop\tds\n"
"\n"
"\t\tmov\tWORD PTR criterr, si\n"
"\t\tmov\tWORD PTR criterr [2], ax\n"
"\n"
"\t\tmov\tah, 34h\t\t; Obtain critical section flag.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR critsec, bx\n"
"\t\tmov\tWORD PTR critsec [2], es\n"
"\n"
"\t\tpush\tcs\n"
"\t\tpop\tes\n"
"\n"
"\t\tlea\tbx, signature\t; Search for resident copy.\n"
"\t\tnot\tBYTE PTR [bx]\t; Avoid false cache match.\n"
"\t\tmov\tcx, SIGLENGTH\t; Get length of signature.\n"
"\t\tcall\tsearch\t\t; Search for prior copy.\n"
"\t\tmov\tpsp, ax\t\t; Save PSP of prior/current TSR.\n"
"install3:\n"
"\t\tcall\t_skipws\t\t; Skip whitespace.\n"
"\t\tcall\t_parse\t\t; Parse nonwhitespace character.\n"
"\n"
"\t\tcmp\tal, CR\t\t; End of command tail?\n"
"\t\tjnz\tinstall4\t; No, branch.\n"
"\n"
"\t\tmov\tax, psp\t\t; Point ES to resident or ...\n"
"\t\tmov\tes, ax\t\t; ... current segment.\n"
"\n"
"\t\tmov\tal, es:key\t; Get hotkey character.\n"
"\t\tmov\ttsr_keymsg1, al\n"
"\n"
"\t\tpush\tcs\t\t; Restore ES if necessary.\n"
"\t\tpop\tes\n"
"\n"
"\t\tlea\tdx, tsr_keymsg\t; Display hotkey message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, cs\t\t; First install?\n"
"\t\tcmp\tax, psp\n"
"\t\tjz\tinstall10\t; Yes, branch.\n"
"\n"
"\t\tmov\tax, 4c00h\t; Exit with OK code.\n"
"\t\tint\t21h\n"
"install4:\n"
"\t\tcmp\tal, '/'\t\t; Option?\n"
"\t\tjz\tinstall5\t; Yes, branch.\n"
"\n"
"\t\tlea\tdx, tsr_errmsg2\t; Display error message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 4c01h\t; Exit with error code 1.\n"
"\t\tint\t21h\n"
"install5:\n"
"\t\tcall\t_parse\t\t; Extract next character.\n"
"\t\tcall\tupper\t\t; Convert to uppercase.\n"
"\n"
"\t\tcmp\tal, 'B'\t\t; Beep option?\n"
"\t\tjnz\tinstall6\t; No, branch.\n"
"\n"
"\t\tcall\tparse_beep\t; Parse beep option.\n"
"\t\tjmp\tSHORT install3\n"
"install6:\n"
"\t\tcmp\tal, 'K'\t\t; Hotkey option?\n"
"\t\tjnz\tinstall7\t; No, branch.\n"
"\n"
"\t\tcall\tparse_key\t; Parse hotkey option.\n"
"\t\tjmp\tSHORT install3\n"
"install7:\n"
"\t\tcmp\tal, 'U'\t\t; Uninstall option?\n"
"\t\tjnz\tinstall9\t; No, branch.\n"
"\n"
"\t\tmov\tax, cs\t\t; First install?\n"
"\t\tcmp\tax, psp\n"
"\t\tjnz\tinstall8\t; No, branch.\n"
"\n"
"\t\tlea\tdx, tsr_errmsg4\t; Display error message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 4c01h\t; Exit with error code 1.\n"
"\t\tint\t21h\n"
"install8:\n"
"\t\tjmp\tuninstall\n"
"install9:\n";
/* --------------------------------------------------------------------- */
char *listing8_1 =
"\t\tpush\tax\n"
"\t\tcall\t_xparse\t\t; Extended parsing.\n"
"\t\tpop\tcx\n"
"\n"
"\t\tor\tax, ax\t\t; Parse error?\n"
"\t\tjz\tinstall3\t; No, branch.\n"
"\n";
/* --------------------------------------------------------------------- */
char *listing8_2 =
"\t\tlea\tdx, tsr_errmsg3\t; Display error message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 4c01h\t; Exit with error code 1.\n"
"\t\tint\t21h\n"
"install10:\n";
/* --------------------------------------------------------------------- */
char *listing9 =
"\t\tcall\t_setup\t\t; Attempt additional setup.\n"
"\n"
"\t\tor\tax, ax\t\t; Setup successful?\n"
"\t\tjz\tinstall11\t; Yes, branch.\n"
"\n"
"\t\tlea\tdx, tsr_errmsg7\t; Display error message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 4c01h\t; Exit with error code 1.\n"
"\t\tint\t21h\n"
"install11:\n";
/* --------------------------------------------------------------------- */
char *listing10 =
"\t\tcmp\tBYTE PTR ver, 5\t; Version number at least 5.0?\n"
"\t\tjb\tinstall11_5\t; No, branch.\n"
"\n"
"\t\tmov\tax, 4300h\t; Get HIMEM.SYS installed state.\n"
"\t\tint\t2fh\n"
"\n"
"\t\tor\tal, al\t\t; Installed?\n"
"\t\tjz\tinstall11_5\t; No, branch.\n"
"\n"
"\t\tmov\tax, 4310h\t; Get entry point address.\n"
"\t\tint\t2fh\n"
"\n"
"\t\tmov\tWORD PTR XMS_driver, bx\n"
"\t\tmov\tWORD PTR XMS_driver [2], es\n"
"install11_5:\n"
"\t\tmov\tax, 3508h\t; Get timer hard interrupt vector.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint8h, bx\n"
"\t\tmov\tWORD PTR oldint8h [2], es\n"
"\n"
"\t\tmov\tax, 3509h\t; Get key hard interrupt vector.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint9h, bx\n"
"\t\tmov\tWORD PTR oldint9h [2], es\n"
"\n"
"\t\tmov\tax, 3513h\t; Get disk interrupt vector.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint13h, bx\n"
"\t\tmov\tWORD PTR oldint13h [2], es\n"
"\n"
"\t\tmov\tax, 3516h\t; Get key soft interrupt vector.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint16h, bx\n"
"\t\tmov\tWORD PTR oldint16h [2], es\n"
"\n"
"\t\tmov\tax, 351ch\t; Get timer soft interrupt vector.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint1ch, bx\n"
"\t\tmov\tWORD PTR oldint1ch [2], es\n"
"\n"
"\t\tmov\tax, 3528h\t; Get idle interrupt vector.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint28h, bx\n"
"\t\tmov\tWORD PTR oldint28h [2], es\n"
"\n"
"\t\tmov\tax, 352fh\t; Get mux interrupt vector.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR oldint2fh, bx\n"
"\t\tmov\tWORD PTR oldint2fh [2], es\n"
"\n"
"\t\tmov\tax, ds:[002ch]\t; Attempt to free environment.\n"
"\t\tcmp\tax, 0\t\t; Can we free environment?\n"
"\t\tjz\tinstall12\t; No, branch.\n"
"\n"
"\t\tmov\tes, ax\t ; Free environment block.\n"
"\t\tmov\tah, 49h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tWORD PTR ds:[002ch], 0\t; Indicate no environment.\n"
"install12:\n"
"\t\tmov\tax, 2508h\t; Set new timer interrupt vector.\n"
"\t\tlea\tdx, newint8h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 2513h\t; Set new disk interrupt vector.\n"
"\t\tlea\tdx, newint13h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 2528h\t; Set new idle interrupt vector.\n"
"\t\tlea\tdx, newint28h\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 252fh\t; Set new mux interrupt vector.\n"
"\t\tlea\tdx, newint2fh\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 2509h\t; Set new key interrupt vector.\n"
"\t\tlea\tdx, newint9h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlea\tdx, installsec\t; Calculate number of para- ...\n"
"\t\tadd\tdx, 15\t\t; ... graphs to keep resident.\n"
"\t\tmov\tcl, 4\n"
"\t\tshr\tdx, cl\n"
"\n"
"\t\tmov\tax, 3100h\t; TSR.\n"
"\t\tint\t21h\n"
"\n"
"; -------------------- ;\n"
"; Installation Support ;\n"
"; -------------------- ;\n"
"\n"
"; ---------------------------------------------- ;\n"
"; Convert: Convert hotkey character to scancode. ;\n"
"; ;\n"
"; Entry: AL = character ('A'-'Z' or '0'-'9') ;\n"
"; ;\n"
"; Exit: AL = scancode ;\n"
"; ;\n"
"; All other registers preserved. ;\n"
"; Requires presence of scancodes array. ;\n"
"; ---------------------------------------------- ;\n"
"\n"
"convert\t\tPROC\tNEAR\n"
"\t\tpush\tbx\n"
"\n"
"\t\tmov\tbl, al\t\t; Get hotkey character.\n"
"\t\txor\tbh, bh\n"
"\n"
"\t\tcmp\tbl, 'A'\t\t; Alphabetic hotkey?\n"
"\t\tjb\tconvert1\t; No, branch.\n"
"\n"
"\t\tsub\tbl, 'A'\t\t; Get alphabetic scancode.\n"
"\t\tmov\tal, scancodes [bx]\n"
"\n"
"\t\tpop\tbx\n"
"\n"
"\t\tret\n"
"convert1:\n"
"\t\tsub\tbl, '0'\t\t; Get digit scancode.\n"
"\t\tmov\tal, scancodes [bx+26]\n"
"\n"
"\t\tpop\tbx\n"
"\n"
"\t\tret\n"
"convert\t\tENDP\n"
"\n"
"; ------------------------------------- ;\n"
"; Parse: Parse nonwhitespace character. ;\n"
"; ;\n"
"; Entry: none ;\n"
"; ;\n"
"; Exit: AX = character ;\n"
"; ;\n"
"; All other registers preserved. ;\n"
"; ------------------------------------- ;\n"
"\n"
"_parse\t\tPROC\tNEAR\n"
"\t\tpush\tbx\n"
"\n"
"\t\tmov\tbx, ctailaddr\t; Get command tail address.\n"
"\t\tmov\tal, [bx]\t; Get character at this address.\n"
"\t\tmov\tah, 0\n"
"\n"
"\t\tcmp\tal, CR\t\t; End of command tail?\n"
"\t\tjz\tparse1\t\t; Yes, branch.\n"
"\n"
"\t\tinc\tbx\t\t; Point to next character.\n"
"\t\tmov\tctailaddr, bx\t; Update command tail address.\n"
"parse1:\n"
"\t\tpop\tbx\n"
"\n"
"\t\tret\n"
"_parse\t\tENDP\n"
"\n"
"; --------------------------- ;\n"
"; Parse_beep: Parse B option. ;\n"
"; ;\n"
"; Entry: none ;\n"
"; ;\n"
"; Exit: none ;\n"
"; ;\n"
"; All registers preserved. ;\n"
"; --------------------------- ;\n"
"\n"
"parse_beep\tPROC\tNEAR\n"
"\t\tpush\tax\n"
"\t\tpush\tes\n"
"\n"
"\t\tcall\t_parse\t\t; Parse character after B.\n"
"\n"
"\t\tcmp\tal, '0'\t\t; Disable beeping?\n"
"\t\tjb\tparse_beep1\t; No, branch.\n"
"\n"
"\t\tcmp\tal, '1'\t\t; Disable or enable beeping?\n"
"\t\tjbe\tparse_beep2\t; Yes, branch.\n"
"parse_beep1:\n"
"\t\tlea\tdx, tsr_errmsg3\t; Display error message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tpop\tes\t\t; Cleanup stack even though ...\n"
"\t\tpop\tax\t\t; ... we don't have to.\n"
"\n"
"\t\tmov\tax, 4c01h\t; Exit with error code 1.\n"
"\t\tint\t21h\n"
"parse_beep2:\n"
"\t\tpush\tax\n"
"\n"
"\t\tmov\tax, psp\t\t; Point ES to resident segment.\n"
"\t\tmov\tes, ax\n"
"\n"
"\t\tpop\tax\n"
"\n"
"\t\tsub\tal, '0'\t\t; Convert ASCII to binary.\n"
"\t\tmov\tes:beepf, al\t; Save character.\n"
"\n"
"\t\tpop\tes\n"
"\t\tpop\tax\n"
"\n"
"\t\tret\n"
"parse_beep\tENDP\n"
"\n"
"; -------------------------- ;\n"
"; Parse_key: Parse K option. ;\n"
"; ;\n"
"; Entry: none ;\n"
"; ;\n"
"; Exit: none ;\n"
"; ;\n"
"; All registers preserved. ;\n"
"; -------------------------- ;\n"
"\n"
"parse_key\tPROC\tNEAR\n"
"\t\tpush\tax\n"
"\t\tpush\tes\n"
"\n"
"\t\tcall\t_parse\t\t; Parse character after K.\n"
"\n"
"\t\tcmp\tal, 'a'\t\t; Convert to uppercase.\n"
"\t\tjb\tparse_key1\n"
"\n"
"\t\tcmp\tal, 'z'\n"
"\t\tja\tparse_key1\n"
"\n"
"\t\tsub\tal, 32\n"
"parse_key1:\n"
"\t\tcmp\tal, '0'\t\t; Validate.\n"
"\t\tjb\tparse_key2\n"
"\n"
"\t\tcmp\tal, 'Z'\n"
"\t\tja\tparse_key2\n"
"\n"
"\t\tcmp\tal, '9'\n"
"\t\tjbe\tparse_key3\n"
"\n"
"\t\tcmp\tal, 'A'\n"
"\t\tjae\tparse_key3\n"
"parse_key2:\n"
"\t\tlea\tdx, tsr_errmsg6\t; Display error message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tpop\tes\t\t; Cleanup stack even though ...\n"
"\t\tpop\tax\t\t; ... we don't have to.\n"
"\n"
"\t\tmov\tax, 4c01h\t; Exit with error code 1.\n"
"\t\tint\t21h\n"
"parse_key3:\n"
"\t\tpush\tax\n"
"\n"
"\t\tmov\tax, psp\t\t; Point ES to resident segment.\n"
"\t\tmov\tes, ax\n"
"\n"
"\t\tpop\tax\n"
"\n"
"\t\tmov\tes:key, al\t; Save character.\n"
"\n"
"\t\tcall\tconvert\t\t; Convert character to scancode.\n"
"\n"
"\t\tmov\tes:scancode, al\t; Save scancode.\n"
"\n"
"\t\tpop\tes\n"
"\t\tpop\tax\n"
"\n"
"\t\tret\n"
"parse_key\tENDP\n"
"\n"
"; ------------------------------------------------ ;\n"
"; Search: Search memory for previous TSR copy. ;\n"
"; ;\n"
"; Entry: BX = address of signature to search ;\n"
"; CX = length of signature ;\n"
"; ;\n"
"; Exit: AX = PSP address of prior or current copy ;\n"
"; ;\n"
"; All registers preserved (direction flag cleared) ;\n"
"; ------------------------------------------------ ;\n"
"\n"
"search\t\tPROC\tNEAR\n"
"\t\tpush\tbx\n"
"\t\tpush\tcx\n"
"\t\tpush\tsi\n"
"\t\tpush\tdi\n"
"\t\tpush\tes\n"
"\n"
"\t\tmov\tsi, bx\t\t; SI will point to signature.\n"
"\n"
"\t\tmov\tax, 0a000h\t; Initial segment.\n"
"\t\tmov\tbx, cs\t\t; Final segment.\n"
"\t\tcld\t\t\t; Forward string operations.\n"
"search1:\n"
"\t\tinc\tax\t\t; Point to next segment.\n"
"\n"
"\t\tcmp\tax, bx\t\t; At current segment?\n"
"\t\tjz\tsearch2\t\t; Yes, exit search.\n"
"\n"
"\t\tmov\tes, ax\t\t; Target segment.\n"
"\t\tmov\tdi, si\t\t; Same offset.\n"
"\n"
"\t\tpush\tcx\t\t; CMPSB destroys CX and SI.\n"
"\t\tpush\tsi\n"
"\n"
"\t\trep\tcmpsb\t\t; Search for match.\n"
"\n"
"\t\tpop\tsi\n"
"\t\tpop\tcx\n"
"\n"
"\t\tjnz\tsearch1\t\t; Branch if no match.\n"
"search2:\n"
"\t\tpop\tes\n"
"\t\tpop\tdi\n"
"\t\tpop\tsi\n"
"\t\tpop\tcx\n"
"\t\tpop\tbx\n"
"\n"
"\t\tret\n"
"search\t\tENDP\n"
"\n"
"; --------------------------------------- ;\n"
"; Setcseg: Set DS and ES regs to cur seg. ;\n"
"; ;\n"
"; Entry: none ;\n"
"; ;\n"
"; Exit: none ;\n"
"; ;\n"
"; All registers preserved. ;\n"
"; --------------------------------------- ;\n"
"\n"
"_setcseg\tPROC\tNEAR\n"
"\t\tpush\tcs\n"
"\t\tpop\tds\n"
"\n"
"\t\tpush\tcs\n"
"\t\tpop\tes\n"
"\n"
"\t\tret\n"
"_setcseg\tENDP\n"
"\n"
"; --------------------------------------- ;\n"
"; Setrseg: Set DS and ES regs to res seg. ;\n"
"; ;\n"
"; Entry: none ;\n"
"; ;\n"
"; Exit: none ;\n"
"; ;\n"
"; All registers preserved. ;\n"
"; --------------------------------------- ;\n"
"\n"
"_setrseg\tPROC\tNEAR\n"
"\t\tmov\tds, psp\n"
"\t\tmov\tes, psp\n"
"\n"
"\t\tret\n"
"_setrseg\tENDP\n"
"\n"
"; ---------------------------------------- ;\n"
"; Skipws: Skip whitespace on command tail. ;\n"
"; ;\n"
"; Entry: none ;\n"
"; ;\n"
"; Exit: none ;\n"
"; ;\n"
"; All registers preserved. ;\n"
"; ---------------------------------------- ;\n"
"\n"
"_skipws\t\tPROC\tNEAR\n"
"\t\tpush\tax\n"
"\t\tpush\tbx\n"
"\n"
"\t\tmov\tbx, ctailaddr\t; Get command tail address.\n"
"skipws1:\n"
"\t\tmov\tal, [bx]\t; Get command tail character.\n"
"\n"
"\t\tcmp\tal, ' '\t\t; Is character a space?\n"
"\t\tjz\tskipws2\t\t; Yes, skip character.\n"
"\n"
"\t\tcmp\tal, TAB\t\t; Is character a tab?\n"
"\t\tjnz\tskipws3\t\t; Yes, skip character.\n"
"skipws2:\n"
"\t\tinc\tbx\t\t; Point to next character.\n"
"\t\tjmp\tSHORT skipws1\t; Continue.\n"
"skipws3:\n"
"\t\tmov\tctailaddr, bx\t; Update command tail address.\n"
"\n"
"\t\tpop\tbx\n"
"\t\tpop\tax\n"
"\n"
"\t\tret\n"
"_skipws\t\tENDP\n"
"\n"
"; ---------------------------------- ;\n"
"; Uninstall: Remove TSR from memory. ;\n"
"; ;\n"
"; Entry: none ;\n"
"; ;\n"
"; Exit: does not return ;\n"
"; ---------------------------------- ;\n"
"\n"
"uninstall\tPROC\tNEAR\n"
"\t\tmov\tax, 3508h\t; Make sure timer int exists.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, es\n"
"\t\tcmp\tax, psp\n"
"\t\tjz\tuninstall0\n"
"\n"
"\t\tjmp\tNEAR PTR uninstall1\n"
"uninstall0:\n"
"\t\tmov\tax, 3509h\t; Make sure key int exists.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, es\n"
"\t\tcmp\tax, psp\n"
"\t\tjnz\tuninstall1\n"
"\n"
"\t\tmov\tax, 3513h\t; Make sure disk int exists.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, es\n"
"\t\tcmp\tax, psp\n"
"\t\tjnz\tuninstall1\n"
"\n"
"\t\tmov\tax, 3528h\t; Make sure idle int exists.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, es\n"
"\t\tcmp\tax, psp\n"
"\t\tjnz\tuninstall1\n"
"\n"
"\t\tmov\tax, 352fh\t; Make sure mux int exists.\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, es\n"
"\t\tcmp\tax, psp\n"
"\t\tjnz\tuninstall1\n"
"\n"
"\t\tmov\tax, psp\n"
"\t\tmov\tes, ax\n"
"\n"
"\t\tlds\tdx, es:oldint8h\t; Restore timer int.\n"
"\t\tmov\tax, 2508h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, es:oldint9h\t; Restore key int.\n"
"\t\tmov\tax, 2509h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, es:oldint13h ; Restore disk int.\n"
"\t\tmov\tax, 2513h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, es:oldint28h ; Restore idle int.\n"
"\t\tmov\tax, 2528h\n"
"\t\tint\t21h\n"
"\n"
"\t\tlds\tdx, es:oldint2fh ; Restore mux int.\n"
"\t\tmov\tax, 252fh\n"
"\t\tint\t21h\n"
"\n"
"\t\tpush\tcs\n"
"\t\tpop\tds\n"
"\n"
"\t\tmov\tax, psp\t\t; Get resident PSP segment.\n"
"\t\tmov\tes, ax\n"
"\n";
/* --------------------------------------------------------------------- */
char *listing11 =
"\t\tcall\t_cleanup\t; Cleanup after setup.\n"
"\n"
"\t\tor\tax, ax\t\t; Cleanup successful?\n"
"\t\tjnz\tuninstall3\t; No, branch.\n"
"\n";
/* --------------------------------------------------------------------- */
char *listing12 =
"\t\tmov\tah, 49h\t\t; Free memory.\n"
"\t\tint\t21h\n"
"\t\tjc\tuninstall3\t; Branch on failure.\n"
"\n"
"\t\tlea\tdx, tsr_delmsg\t; Display success message.\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 4c00h\t; Exit with OK code.\n"
"\t\tint\t21h\n"
"uninstall1:\n"
"\t\tlea\tdx, tsr_errmsg5\t; Display error message.\n"
"uninstall2:\n"
"\t\tmov\tah, 9\n"
"\t\tint\t21h\n"
"\n"
"\t\tmov\tax, 4c01h\t; Exit with error code 1.\n"
"\t\tint\t21h\n"
"uninstall3:\n"
"\t\tlea\tdx, tsr_errmsg8\t; Display severe error message.\n"
"\t\tjmp\tSHORT uninstall2\n"
"uninstall\tENDP\n"
"\n"
"; ------------------------------------ ;\n"
"; Unparse: Backup parse pointer by one ;\n"
"; character. ;\n"
"; ;\n"
"; Pointer not backed up if pointing to ;\n"
"; CR or start of buffer. ;\n"
"; ;\n"
"; Entry: none ;\n"
"; ;\n"
"; Exit: none ;\n"
"; ;\n"
"; All other registers preserved. ;\n"
"; ------------------------------------ ;\n"
"\n"
"_unparse\tPROC\tNEAR\n"
"\t\tpush\tbx\n"
"\t\tmov\tbx, ctailaddr\n"
"\n"
"\t\tcmp\tbx, 81h\n"
"\t\tjz\tunparse1\n"
"\n"
"\t\tcmp\tBYTE PTR [bx],\tCR\n"
"\t\tjz\tunparse1\n"
"\n"
"\t\tdec\tbx\n"
"\t\tmov\tctailaddr, bx\n"
"unparse1:\n"
"\t\tpop\tbx\n"
"\n"
"\t\tret\n"
"_unparse\tENDP\n"
"\n"
"; -------------------------------------- ;\n"
"; Upper: Convert character to uppercase. ;\n"
"; ;\n"
"; Entry: AL - character to convert ;\n"
"; ;\n"
"; Exit: AL - converted character ;\n"
"; ;\n"
"; All other registers preserved. ;\n"
"; -------------------------------------- ;\n"
"\n"
"upper\t\tPROC\tNEAR\n"
"\t\tcmp\tal, 'a'\n"
"\t\tjb\tupper1\n"
"\n"
"\t\tcmp\tal, 'z'\n"
"\t\tja\tupper1\n"
"\n"
"\t\tsub\tal, 32\n"
"upper1:\n"
"\t\tret\n"
"upper\t\tENDP\n"
"\n"
"_TEXT\t\tENDS\n"
"\t\tEND\ttsr\n";
char *banner =
"╔═══════════════════════════════════════════════════════════╗\n"
"║ ▒▒▒▒▒ ▒▒▒ ▒▒▒▒▒ ║\n"
"║ ▒ ▒ ▒ ▒ ▒ TSR v1.5 ║\n"
"║ ▒ ▒ ▒ ▒ ║\n"
"║ ▒ ▒▒▒ ▒▒▒▒▒ Copyright (C) 1993, Geoff Friesen B.Sc. ║\n"
"║ ▒ ▒ ▒ ▒ All rights reserved. ║\n"
"║ ▒ ▒ ▒ ▒ ▒ ║\n"
"║ ▒ ▒▒▒ ▒ ▒ ║\n"
"╚═══════════════════════════════════════════════════════════╝\n\n";
int cbreak (void);
void error (char *message);
int map (void);
void usage (void);
void main (int argc, char **argv)
{
FILE *f;
int arg;
int hotkey = 'T';
int include = 0;
int scancode = 0x14;
int setup_cleanup = 0;
int stack = 256;
int xparse = 0;
char drive [MAXDRIVE];
char dir [MAXDIR];
char file [MAXFILE];
char ext [MAXEXT];
char asmspec [MAXPATH];
char tsrspec [MAXPATH];
char scancodes [] =
{
30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, /* A-M */
49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, /* N-Z */
11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 /* 0-9 */
};
ctrlbrk (cbreak); /* Install new CTRL-BREAK/CTRL-C handler */
fprintf (stderr, banner);
if (_osmajor < 3 || _osmajor == 3 && _osminor < 30)
error ("DOS 3.30 or higher required");
if (argc < 2)
usage ();
if (argc == 2 &&
(!stricmp (argv [1], "/m") || !stricmp (argv [1], "-m")))
exit (map ());
for (arg = 1; arg < argc; arg++)
if (*argv [arg] != '/' && *argv [arg] != '-')
break;
else
if (!strnicmp (argv [arg]+1, "h", 1))
{
if (!isalnum(argv [arg] [2]))
error ("alphanumeric hotkey expected");
hotkey = toupper (argv [arg] [2]);
scancode = isalpha(hotkey) ? scancodes [hotkey-'A'] :
scancodes [hotkey-'0'+26];
}
else
if (!stricmp (argv [arg]+1, "i"))
include = 1;
else
if (!strnicmp (argv [arg]+1, "sc", 2))
setup_cleanup = 1;
else
if (!strnicmp (argv [arg]+1, "s", 1))
{
stack = atoi (argv [arg]+2);
if (stack < 256 || stack > 8192)
error ("stack size out of range");
}
else
if (!stricmp (argv [arg]+1, "x"))
xparse = 1;
else
usage ();
if (arg == argc)
error ("tsrspec is missing");
strcpy (tsrspec, argv [argc-1]);
if (!(fnsplit (tsrspec, drive, dir, file, ext) & EXTENSION))
{
strcpy (ext, ".TSR");
fnmerge (tsrspec, drive, dir, file, ext);
}
else
if (stricmp (ext, ".TSR"))
error ("invalid extension (.TSR expected)");
strcpy (ext, ".ASM");
fnmerge (asmspec, drive, dir, file, ext);
if ((f = fopen (asmspec, "wt")) == NULL)
error ("unable to create .ASM file");
if (fprintf (f, "; %s%s", asmspec, listing1) == EOF ||
fprintf (f, "%c%s", hotkey, listing2) == EOF ||
fprintf (f, "%02xh%s", scancode, listing3) == EOF ||
fprintf (f, "\"TSR:%s\"%s", file, listing4) == EOF ||
fprintf (f, "\t\tDB\t%d DUP (?)\n"
"stack_\t\tLABEL\tBYTE\n"
"\n"
"\t\tINCLUDE %s\n", stack, tsrspec) == EOF ||
include && fprintf (f, "\t\tINCLUDE EXTRA.ASM\n") == EOF ||
fprintf (f, "%s", listing5) == EOF ||
setup_cleanup && fprintf (f, "%s", listing6) == EOF ||
fprintf (f, "%s", listing7) == EOF ||
xparse && fprintf (f, "%s", listing8_1) == EOF ||
fprintf (f, "%s", listing8_2) == EOF ||
setup_cleanup && fprintf (f, "%s", listing9) == EOF ||
fprintf (f, "%s", listing10) == EOF ||
setup_cleanup && fprintf (f, "%s", listing11) == EOF ||
fprintf (f, "%s", listing12) == EOF)
error ("unable to write to .ASM file");
(void) fcloseall ();
fprintf (stderr, "tsr: %s successfully generated\n", asmspec);
exit (OK);
}
/* -------------------- */
/* int cbreak (void); */
/* */
/* Disable CTRL-BREAKs. */
/* -------------------- */
int cbreak (void)
{
return IGNORE;
}
/* --------------------------------------------- */
/* void error (char *message); */
/* */
/* Display the specified error message and exit. */
/* --------------------------------------------- */
void error (char *message)
{
(void) fcloseall ();
fprintf (stderr, "tsr: %s\n", message);
exit (ERROR);
}
/* ------------------------------- */
/* int map (void); */
/* */
/* Display a map of resident TSRs. */
/* Return OK or ERROR. */
/* ------------------------------- */
int map (void)
{
char typemcb;
unsigned i, ntsrs = 0, segment = 0x40;
do
{
if (peekb(segment, 0) == BLOCMCB) /* Found first MCB? */
if (peek(segment, 1) == segment+1) /* First MCB owns ... */
break; /* ... following segment */
if (++segment == 0xa000) /* Goto 640K segment ... */
{ /* ... even if less mem */
fprintf (stderr, "tsr: bad MCB chain\n");
return ERROR;
}
}
while (1);
puts ("--- ------ ---");
puts ("PSP HOTKEY TSR");
puts ("--- ------ ---\n");
do
{
if ((~peekb(segment+1, SIGOFS) == 'T') &&
(peekb(segment+1, SIGOFS+1) == 'S') &&
(peekb(segment+1, SIGOFS+2) == 'R'))
{
printf ("%04X ", ++segment); /* Point to PSP */
printf ("ALT-%c ", peekb(segment, KEYOFS));
putchar('T');
for (i = SIGOFS+1; putchar(peekb(segment, i++));)
;
puts ("");
ntsrs++;
segment--; /* Point to MCB */
}
if (peekb(segment, 0) == LASTMCB)
break;
segment += (peek(segment, 3)+1); /* Point to next MCB */
typemcb = peekb(segment, 0); /* Obtain MCB type */
if (typemcb != BLOCMCB && typemcb != LASTMCB)
{
fprintf (stderr, "tsr: bad MCB chain\n");
return ERROR;
}
}
while (1);
if (ntsrs)
puts ("");
printf ("tsr: found %d tsr%s", ntsrs, (ntsrs != 1) ? "s.\n" : ".\n");
return OK;
}
/* --------------------------------------------- */
/* void usage (void); */
/* */
/* Display usage information when user enters an */
/* invalid command-line. Exit program. */
/* --------------------------------------------- */
void usage (void)
{
char *_usage =
"bad command line\n\n"
"Command-line format:\n"
"\n"
"tsr options tsrspec\n"
"\n"
"options = map | [hotkey] [include] [setup_cleanup] [stack] [xparse]\n"
"\n"
"map = (\"/\"|\"-\") \"m\"\n"
"hotkey = (\"/\"|\"-\") \"h\" x\n"
"include = (\"/\"|\"-\") \"i\"\n"
"setup_cleanup = (\"/\"|\"-\") \"sc\"\n"
"stack = (\"/\"|\"-\") \"s\" y\n"
"xparse = (\"/\"|\"-\") \"x\"\n"
"\n"
"x is either \"A\"-\"Z\" or \"0\"-\"9\" (default is T)\n"
"y is a byte value from 256 to 8192 (default is 256)\n"
"tsrspec defines the .TSR file to be TSRed\n";
error (_usage);
}